function SpPopup() {
  var _isShow;
  var _oldKeyDown;
  var _util = Library.WebControl.Util;
  var _hashParameter = Library.WebControl.Hashtable.CreateHashtable();
  var _instance = this;
  var _id;
  var _ownerId;
  var _model;
  var _effectControl;
  var _effectType;
  var _effectTime;
  var _effectStep;
  var _textId;
  var _renderMode = 0;
  var _position = 0; //center screen
  var _closeType;
  var _tid;
  var _oldMouseDown;
  var _shown = null;
  var _hidden = null;
  var _beforeCallback = null;
  this.Init = function(id, clientName, ownerId, model, effectType, effectTime, effectStep, textId, renderMode, position, tid, closeType) {
    _id = id;
    _globalHashObject.Add(clientName, _instance);
    window[clientName] = _instance;
    _ownerId = ownerId;
    _model = model;
    _effectType = effectType;
    _effectStep = effectStep;
    _effectTime = effectTime;
    _textId = textId;
    _renderMode = renderMode;
    _position = position;
    _tid = tid;
    _closeType = closeType;
    _isShow = false;
  };
  function docKeyDown(ev) {
    var key = _util.GetKey(ev);
    if (key == 27) {
      _instance.Hide();
      return true;
    }
    return false;
  };
  this.ShowAt = function() {
    if (arguments.length > 0)
      _ownerId = arguments[0];
    return _ownerId;
  };
  this.AddParameter = function(k, v) {
    _hashParameter.Add(k, v);
  };
  this.Show = function() {
    if (_isShow) return;
    _isShow = true;
    var pup = _util.GetObjectById(_id);
    if (_ownerId != "") {
      var pos = _util.GetPosition(_ownerId);
      var size = _util.GetSize(_ownerId);
      var absParrent = _util.GetAbsParrent(pup);
      if (absParrent != null) {
        var posAbsParrent = _util.GetPosition(absParrent);
        pos.X = pos.X - posAbsParrent.X;
        pos.Y = pos.Y - posAbsParrent.Y;
      }
      var offset = {
        X: pos.X,
        Y: pos.Y + size.H + 3
      };
      var sc = _util.GetParentScrollOffset(_ownerId);
      offset.X -= sc[0];
      offset.Y -= sc[1];

      pup.style.top = offset.Y + 'px';
      pup.style.left = offset.X + 'px';
    }
    else {
      if (_position == 0)
        _util.MoveToCenterScreen(pup);
      else if (_position == 1) {
        _util.MoveToTopCenterScreen(pup);
      }
    }
    if (_model) {
      if (!SpPopup.counter) SpPopup.counter = 1;
      else SpPopup.counter++;
      _util.DisableForm();
    }

    var firstShow = false;
    pup.style.zIndex = _util.GetMaxZindex() + 1; //_zIndex;
    if (!_effectControl) {
      firstShow = true;
      _effectControl = Library.WebControl.Effect.Create({
        Object: pup,
        Type: _effectType,
        Time: _effectTime,
        Step: _effectStep,
        Vision: 'V',
        HideComplete: function(s, e) {
          pup.style.left = "-1000px";
          pup.style.top = "-1000px";
          pup.style.zIndex = 0;
          if (_hidden != null)
            _hidden(_instance, {});
          if (_model) {
            document.onkeydown = _oldKeyDown;
          }
          if (_closeType == 2) {
            document.onmousedown = _oldMouseDown;
          }
        },
        ShowComplete: function(s, e) {
          if (_shown != null)
            _shown(_instance, {});
          if (_model) {
            _oldKeyDown = document.onkeydown;
            document.onkeydown = function(ev) { docKeyDown(ev); };
          }
          if (_closeType == 2) { // outer click
            _oldMouseDown = document.onmousedown;
            document.onmousedown = function(ev) {
              if (_isShow) {
                var mos = _util.GetMousePosition(ev);
                var ppos = _util.GetPosition(pup);
                var pSize = {
                  W: pup.offsetWidth,
                  H: pup.offsetHeight
                };
                if (mos.X < ppos.X || mos.X > ppos.X + pSize.W || mos.Y < ppos.Y || mos.Y > ppos.Y + pSize.H) {
                  _instance.Hide();
                  //setTimeout(function() { document.onmousedown = _oldMouseDown; }, 100);
                  return false;
                }
              }
              return true;
            };
          }
        }
      });
    }
    if (_renderMode == 0 || (_renderMode == 2 && !firstShow)) {
      _effectControl.Show();
    }
    else {
      callback();
    }
  };
  function callback() {
    if (_beforeCallback != null)
      _beforeCallback(_instance, {});
    var ajaxRequest = Library.WebControl.Ajax.CreateRequest();
    ajaxRequest.SetData("__SPPOPUPRQSID_=" + _id + "& " + _hashParameter.ToQuery());
    _hashParameter.Clear();
    ajaxRequest.SendCallback({}, callbackComplete);
  };
  function callbackComplete(s, e) {
    var responseArgs = _util.ParseAjaxResponse(e.ResponseText);
    if (!responseArgs.IsValid) {
      alert(responseArgs.Result);
    }
    else {
      var content = _util.FindLastChild(_id, "div", "pucontent");
      if (content) {
        _util.EvalScriptAndHtml(responseArgs.Data, content);
        setTimeout(function() { _effectControl.Show(); }, 200);
      }
    }
  };
  this.Hide = function() {
    if (!_isShow) return;
    _isShow = false;
    if (_effectControl != null)
      _effectControl.Hide();
    if (_model) {
      SpPopup.counter--;
      if (!SpPopup.counter)
        _util.EnableForm();
    }
  };
  this.SetTitle = function(t) {
    var firstChild = _util.FindFirstChild(_tid, "div", "putitleText");
    if (firstChild) firstChild.innerHTML = t;
  };
  this.AddHandler = function(t, f) {
    switch (t) {
      case 1:
        _shown = f;
        break;
      case 2:
        _hidden = f;
        break;
      case 3:
        _beforeCallback = f;
        break;
    }
  };

};
